﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using MSH.Common.Helpers;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using NHibernate;
using NHibernate.Linq;
using MSH.Common.Business;

namespace MSH.Common.WP7
{
    public enum NotificationType
    {
        Tile = 1,
        Toast = 2,
        Raw = 3
    }

    /// <summary>
    /// De NotificationManager is verantwoordelijke voor het versturen van notificaties
    /// </summary>
    public class NotificationManager
    {
        #region Local constants

        public const string MESSAGE_ID_HEADER = "X-MessageID";
        public const string NOTIFICATION_CLASS_HEADER = "X-NotificationClass";
        public const string NOTIFICATION_STATUS_HEADER = "X-NotificationStatus";
        public const string DEVICE_CONNECTION_STATUS_HEADER = "X-DeviceConnectionStatus";
        public const string SUBSCRIPTION_STATUS_HEADER = "X-SubscriptionStatus";
        public const string WINDOWSPHONE_TARGET_HEADER = "X-WindowsPhone-Target";
        public const int MAX_PAYLOAD_LENGTH = 1024;

        #endregion

        private static NotificationManager current = new NotificationManager();

        /// <summary>
        /// Opvragen van de NotificatieManager
        /// </summary>
        public static NotificationManager Current
        {
            get { return current; }
        }

        /// <summary>
        /// Stuur een notificatie
        /// </summary>
        /// <param name="notification">Notificatie</param>
        /// <param name="channelUri">Url van de client waar de notificatie heen moet</param>
        private void Notify(Notification notification, Uri channelUri)
        {
            if (notification.Data.Length > MAX_PAYLOAD_LENGTH)
            {
                LogHelper.LogMessage("WP7 NotificationManager: Payload is too long. Maximum payload size shouldn't exceed " + MAX_PAYLOAD_LENGTH.ToString() + " bytes");
                return;
            }

            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(channelUri);

                request.Method = WebRequestMethods.Http.Post;
                request.ContentType = "text/xml; charset=utf-8";
                request.ContentLength = notification.Data.Length;
                request.Headers[MESSAGE_ID_HEADER] = Guid.NewGuid().ToString();
                request.Headers[NOTIFICATION_CLASS_HEADER] = ((int)notification.Type).ToString();

                if (notification.Type == NotificationType.Toast)
                    request.Headers[WINDOWSPHONE_TARGET_HEADER] = "toast";
                else if (notification.Type == NotificationType.Tile)
                    request.Headers[WINDOWSPHONE_TARGET_HEADER] = "token";

                request.BeginGetRequestStream(
                    (ar) =>
                    {
                        Stream requestStream = request.EndGetRequestStream(ar);

                        requestStream.BeginWrite(notification.Data, 0, notification.Data.Length,
                            (iar) =>
                            {
                                requestStream.EndWrite(iar);
                                requestStream.Close();

                                request.BeginGetResponse((iarr) =>
                                {
                                    try
                                    {
                                        using (WebResponse response = request.EndGetResponse(iarr))
                                        {
                                            string notificationStatus = response.Headers["X-NotificationStatus"];
                                            string notificationChannelStatus = response.Headers["X-SubscriptionStatus"];
                                            string deviceConnectionStatus = response.Headers["X-DeviceConnectionStatus"];

                                            LogHelper.LogMessage("WP7 NotificationManager: {0}: notificationStatus: {1}", notification.Type.ToString(), notificationStatus);
                                            LogHelper.LogMessage("WP7 NotificationManager: {0}: notificationChannelStatus: {1}", notification.Type.ToString(), notificationChannelStatus);
                                            LogHelper.LogMessage("WP7 NotificationManager: {0}: deviceConnectionStatus: {1}", notification.Type.ToString(), deviceConnectionStatus);
                                            LogHelper.LogMessage("WP7 NotificationManager: {0}: SUCCESS", notification.Type.ToString());
                                        }
                                    }
                                    catch (WebException ex)
                                    {
                                        
                                        if (ex.Status == WebExceptionStatus.ProtocolError)
                                            NotificationManager.Current.Unsubscribe(channelUri.AbsoluteUri);
                                        
                                    }
                                },
                                null);
                            },
                            null);
                    },
                    null);
            }
            catch (WebException ex)
            {
                if (ex.Status == WebExceptionStatus.ProtocolError)
                {
                    LogHelper.LogMessage("WP7 NotificationManager: {0}: FAILED: {1}", notification.Type.ToString(), ex.Message);
                }

                throw;
            }
        }

        /// <summary>
        /// Stuur een notificatie parallel
        /// </summary>
        /// <param name="notification">Notificatie</param>
        /// <param name="channelUri">Url van de client waar de notificatie heen moet</param>
        public void Notify(String uri, Notification notification)
        {
            if (String.IsNullOrEmpty(uri))
                return;
            Parallel.Invoke(() => this.Notify(notification, new Uri(uri)));
        }

        /// <summary>
        /// Usersessie verwijderen aan de hand van de WP7Notificatie uri
        /// </summary>
        /// <param name="uri">WP7 client uri</param>
        public void Unsubscribe(String uri)
        {
            if (String.IsNullOrEmpty(uri))
                return;

            using (ISession session = NHibernateHelper.GetSessionFactory().OpenSession())
            {

                List<UserSession> list = session.Query<UserSession>().Where<UserSession>(us => us.WP7PushNotifactionURL == uri).ToList<UserSession>();
                foreach (UserSession us in list)
                    session.Delete(us);

                using (ITransaction transaction = session.BeginTransaction())
                {
                    transaction.Commit();
                }



            }

        }
       


    }
}
